﻿using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Script.Serialization;

using Gonte.Data;
using Gonte.Data.DataService;
using Gonte.Desktop.ExtJs;

namespace Gonte.Desktop.Web.Controllers
{
    public class EntityController 
        : Controller
    {
        /// <summary>
        /// Selects the collection of records for the grid
        /// </summary>
        /// <param name="typeName">The full name of the entity</param>
        /// <param name="start">Starting row</param>
        /// <param name="limit">Number of rows to retrieve</param>
        /// <param name="filter">Filter to filter the record</param>
        /// <returns>The collection of records as a record store</returns>
        public ActionResult GetCollection(string typeName, int start, int limit, DataFilter filter)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                DataStore store = SessionHelper.DataService.GetCollection(typeName, start, limit, filter);
                env.count = store.Count;

                return store.ToJson();

            }).ToJson());
        }

        /// <summary>
        /// Retrieves an object by its id
        /// </summary>
        /// <param name="typeName">The full name of the entity</param>
        /// <param name="identifiers">The identifiers of the object</param>
        /// <returns>The record</returns>
        public ActionResult GetObject(string typeName, string identifiers)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                IList<DataField> ids = GetIdentifiers(identifiers);

                IList<DataField> data = SessionHelper.DataService.GetObject(typeName, ids);

                return data.ToJson();

            }).ToJson());
        }

        /// <summary>
        /// Inserts a new object
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="record"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Insert(string typeName, FormCollection data)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                DataRecord record = CreateDataRecord(data);

                IList<DataField> identifiers = SessionHelper.DataService.Insert(typeName, record);

                return identifiers.ToJson();

            }).ToJson());
        }

        /// <summary>
        /// Updates an object
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="data"></param>
        /// <param name="identifiers"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Update(string typeName, FormCollection data, string identifiers)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                DataRecord record = CreateDataRecord(data);
                record.Identifiers = GetIdentifiers(identifiers);

                SessionHelper.DataService.Update(typeName, record);

                return null;

            }).ToJson());
        }

        /// <summary>
        /// Deletes an object by its identifier
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="identifiers"></param>
        /// <returns></returns>
        [HttpDelete]
        public ActionResult Delete(string typeName, string identifiers)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                IList<DataField> ids = GetIdentifiers(identifiers);

                SessionHelper.DataService.Delete(typeName, ids);

                return null;

            }).ToJson());
        }

        #region Complex attribute

        /// <summary>
        /// Retrieves the complex object of the entity with typename
        /// </summary>
        /// <param name="typeName">The name of the entity this complex object belongs to</param>
        /// <param name="attributeName"></param>
        /// <param name="identifiers"></param>
        /// <returns></returns>
        public ActionResult GetComplexObject(string typeName, string attributeName, string identifiers)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                IList<DataField> ids = GetIdentifiers(identifiers);

                IList<DataField> data = SessionHelper.DataService.GetObject(typeName, attributeName, ids);
                env.count = data == null ? 0 : data.Count;

                return data.ToJson();

            }).ToJson());
        }

        [HttpPost]
        public ActionResult Set(string typeName, string attributeName, FormCollection data, string identifiers)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                DataRecord record = CreateDataRecord(data);
                IList<DataField> ids = DataField.Parse(identifiers);

                SessionHelper.DataService.Set(typeName, attributeName, ids, record);

                return null;

            }).ToJson());
        }
        
        #endregion

        #region Collection attributes

        public ActionResult GetCollectionAttribute(string typeName, string attributeName, int start, int limit, string identifiers)
        {
            return Content(new Envelope<string>(SessionHelper.SessionVerifier).Process((env) =>
            {
                IList<DataField> ids = GetIdentifiers(identifiers);
                DataStore store = SessionHelper.DataService.GetCollection(typeName, attributeName, start, limit, ids);
                env.count = store.Count;

                return store.ToJson();

            }).ToJson());
        }
        
        #endregion

        #region Helpers

        private IList<DataField> GetIdentifiers(string identifiers)
        {
            if (!identifiers.Contains("["))
            {
                identifiers = string.Format("[{0}]", identifiers); // Convert to array
            }

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            return serializer.Deserialize<List<DataField>>(identifiers);
        }

        private DataRecord CreateDataRecord(FormCollection data)
        {
            DataRecord record = new DataRecord
            {
                Fields = new List<DataField>()
            };

            foreach (string key in data.AllKeys)
            {
                if (key == "typeName"
                    || key == "attributeName"
                    || key == "identifiers")
                {
                    continue;
                }

                DataField field = new DataField
                {
                    Name = key,
                    Value = data[key]
                };

                record.Fields.Add(field);
            }

            return record;
        } 

        #endregion
    }
}
